package ace.cmp.data.methodname.method.name.sql.entity.resolver.impl.property;

import ace.cmp.data.methodname.method.name.sql.core.enums.SqlCommandTypeEnum;
import ace.cmp.data.methodname.method.name.sql.entity.model.EntityMapping;
import ace.cmp.data.methodname.method.name.sql.entity.model.EntityPropertyMapping;
import ace.cmp.data.methodname.method.name.sql.entity.resolver.property.EntityMethodNameToQueryPropertyResolver;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.SneakyThrows;

/**
 * @author caspar
 * @date 2023/2/18 11:17 从方法解析实体选择的属性元数据
 */
public abstract class AbstractSelectQueryPropertyResolver
    implements EntityMethodNameToQueryPropertyResolver {
  private final Method method;
  private final EntityMapping entityMapping;
  private final SqlCommandTypeEnum sqlCommandType;

  public AbstractSelectQueryPropertyResolver(
      SqlCommandTypeEnum sqlCommandType, Method method, EntityMapping entityMapping) {
    this.method = method;
    this.entityMapping = entityMapping;
    this.sqlCommandType = sqlCommandType;
  }

  @SneakyThrows
  @Override
  public List<EntityPropertyMapping> getProperties() {
    Type resolveType = this.resolveClass();
    if (Objects.isNull(resolveType)) {
      return new ArrayList<>();
    }
    Class resolveClass = Class.forName(resolveType.getTypeName());
    return Arrays.stream(resolveClass.getDeclaredFields())
        .map(field -> this.entityMapping.getPropertyMappingByProperty(field.getName()))
        .filter(p -> p.isPresent())
        .map(p -> p.get())
        .collect(Collectors.toList());
  }

  @Override
  public Boolean getSupport() {
    return SqlCommandTypeEnum.SELECT.equals(this.getSqlCommandType());
  }

  /**
   * 获取需要解析的实体对象类型
   *
   * @return
   */
  protected abstract Class resolveClass();

  protected SqlCommandTypeEnum getSqlCommandType() {
    return this.sqlCommandType;
  }

  protected Method getMethod() {
    return this.method;
  }

  protected EntityMapping getEntityMapping() {
    return this.entityMapping;
  }

  protected boolean isNotCustomClass(Class cls) {
    boolean isJavaClass = cls != null && cls.getClassLoader() == null;
    if (cls != null
        && (cls.isAnnotation()
            || cls.isEnum()
            || cls.isInterface()
            || cls.isHidden()
            || cls.isArray()
            || cls.isPrimitive()
            || isJavaClass == true)) {
      return true;
    }
    return false;
  }
}
